package cn.vehicle.biz.impl;

import cn.vehicle.biz.TransportVehicleBiz;
import cn.vehicle.biz.event.VehicleChangeEvent;
import cn.vehicle.domains.bo.QueryCommonVehicleBo;
import cn.vehicle.domains.bo.QueryTransportVehicleBo;
import cn.vehicle.domains.entity.CommonVehicleEntity;
import cn.vehicle.domains.entity.TransportVehicleEntity;
import cn.vehicle.domains.vo.BasePage;
import cn.vehicle.domains.vo.req.vehicle.AddTransportVehicleReq;
import cn.vehicle.domains.vo.req.vehicle.TransportVehicleListReq;
import cn.vehicle.domains.vo.req.vehicle.UpdateTransportVehicleReq;
import cn.vehicle.domains.vo.res.vehicle.TransportVehicleRes;
import cn.vehicle.enums.GovUploadStatus;
import cn.vehicle.enums.VehicleTypeEnum;
import cn.vehicle.exception.VehicleAccessException;
import cn.vehicle.service.CommonVehicleService;
import cn.vehicle.service.TransportVehicleService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 运输车辆业务实现类
 * <p>
 * 负责运输车辆的新增、修改、删除、查询、分页查询等业务逻辑。
 * 同时自动维护与普通车辆表的关联关系（普通车辆作为基础信息表）。
 * </p>
 *
 * <p>设计约定：</p>
 * <ul>
 *   <li>每个运输车辆对应一条普通车辆记录，associationId 进行关联；</li>
 *   <li>删除与更新时需保证两表数据一致；</li>
 *   <li>新增时自动初始化政府上报状态为 INIT。</li>
 * </ul>
 */
@Slf4j
@Service
public class TransportVehicleBizImpl implements TransportVehicleBiz {

    @Resource
    private TransportVehicleService transportVehicleService;

    @Resource
    private CommonVehicleService commonVehicleService;

    @Resource
    private ApplicationEventPublisher publisher;

    /**
     * 新增运输车辆
     *
     * <p>逻辑说明：</p>
     * <ol>
     *   <li>拷贝请求参数生成运输车辆实体并初始化上报状态；</li>
     *   <li>保存运输车辆记录；</li>
     *   <li>同步生成对应普通车辆记录（用于通用车辆管理模块）。</li>
     * </ol>
     *
     * @param req 新增请求参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addTransportVehicle(AddTransportVehicleReq req) {
        // 1. 将请求参数拷贝为运输车辆实体对象
        TransportVehicleEntity transportVehicleEntity = new TransportVehicleEntity();
        BeanUtils.copyProperties(req, transportVehicleEntity);
        // 初始化政府上报状态为 INIT
        transportVehicleEntity.setGovUploadStatus(GovUploadStatus.INIT.name());

        // 保存运输车辆记录
        transportVehicleService.addTransportVehicle(transportVehicleEntity);

        // 2. 同步生成普通车辆记录，保持与运输车辆信息一致
        CommonVehicleEntity commonVehicleEntity = new CommonVehicleEntity();
        BeanUtils.copyProperties(req, commonVehicleEntity);

        commonVehicleEntity.setVehicleType(VehicleTypeEnum.TRANSPORT.name());
        // 绑定普通车辆与运输车辆的关联关系
        commonVehicleEntity.setAssociationId(transportVehicleEntity.getId());
        commonVehicleService.addCommonVehicle(commonVehicleEntity);

        // 创建车辆变更事件对象，携带新建普通车辆的ID
        // 用于在车辆新增后异步触发上报或其他后续处理逻辑
        VehicleChangeEvent vehicleChangeEvent = new VehicleChangeEvent(this, commonVehicleEntity.getId());
        // 发布车辆变更事件，通知监听器执行车辆上报任务（异步调用）
        publisher.publishEvent(vehicleChangeEvent);

    }


    /**
     * 更新运输车辆信息
     *
     * <p>更新时需同步更新关联的普通车辆信息，保持一致性。</p>
     *
     * @param req 更新请求参数，需包含主键ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTransportVehicle(UpdateTransportVehicleReq req) {
        // 校验运输车辆是否存在
        checkTransportVehicleExist(req.getId());

        // 构造运输车辆更新实体并拷贝属性
        TransportVehicleEntity updateEntity = new TransportVehicleEntity();
        BeanUtils.copyProperties(req, updateEntity);
        transportVehicleService.updateTransportVehicle(updateEntity);

        // 查询对应的普通车辆记录，用于同步更新
        CommonVehicleEntity commonVehicleEntity = checkCommonVehicle(req.getId());

        CommonVehicleEntity updateCommonEntity = new CommonVehicleEntity();
        BeanUtils.copyProperties(req, updateCommonEntity);
        updateCommonEntity.setId(commonVehicleEntity.getId());
        // 更新普通车辆表，保持信息一致
        commonVehicleService.updateCommonVehicle(updateCommonEntity);

        // 创建车辆变更事件对象，携带已更新普通车辆的ID
        // 用于在车辆信息修改后触发上报或同步操作
        VehicleChangeEvent vehicleChangeEvent = new VehicleChangeEvent(this, commonVehicleEntity.getId());
        // 发布车辆变更事件，通知事件监听器处理车辆信息更新后的业务逻辑
        publisher.publishEvent(vehicleChangeEvent);
    }

    /**
     * 校验运输车辆是否存在
     *
     * @param id 主键ID
     * @return 存在的实体
     * @throws VehicleAccessException 不存在时抛出异常
     */
    private TransportVehicleEntity checkTransportVehicleExist(Long id) {
        TransportVehicleEntity transportVehicleEntity = transportVehicleService.getTransportVehicleById(id);

        if (transportVehicleEntity == null) {
            throw VehicleAccessException.DATE_NOT_EXIST.newInstance("运输车辆不存在");
        }

        return transportVehicleEntity;
    }


    /**
     * 删除运输车辆（同时删除关联的普通车辆记录）
     *
     * @param id 运输车辆主键ID
     */
    @Override
    public void deleteTransportVehicle(Long id) {
        checkTransportVehicleExist(id);

        // 校验普通车辆信息是否存在（保证两表完整）
        CommonVehicleEntity commonVehicleEntity = checkCommonVehicle(id);

        // 删除运输车辆记录
        transportVehicleService.deleteTransportVehicle(id);
        // 删除关联的普通车辆记录
        commonVehicleService.deleteCommonVehicle(commonVehicleEntity.getId());
    }

    private CommonVehicleEntity checkCommonVehicle(Long id) {
        CommonVehicleEntity commonVehicleEntity = commonVehicleService.getCommonVehicleByAssociationId(id);

        if (commonVehicleEntity == null) {
            throw VehicleAccessException.DATE_NOT_EXIST.newInstance("普通车辆信息不存在");
        }
        return commonVehicleEntity;
    }



    /**
     * 根据ID查询运输车辆详情
     *
     * <p>同时合并运输车辆表与普通车辆表的字段，生成完整信息。</p>
     *
     * @param id 车辆主键ID
     * @return 运输车辆详情信息
     */
    @Override
    public TransportVehicleRes getTransportVehicleById(Long id) {

        TransportVehicleRes transportVehicleRes = new TransportVehicleRes();

        // 查询运输车辆信息并校验存在
        TransportVehicleEntity transportVehicleEntity = checkTransportVehicleExist(id);

        BeanUtils.copyProperties(transportVehicleEntity, transportVehicleRes);

        CommonVehicleEntity commonVehicleEntity = checkCommonVehicle(id);

        // 合并普通车辆的基础字段（如车牌、品牌、单位等）
        BeanUtils.copyProperties(commonVehicleEntity, transportVehicleRes);
        return transportVehicleRes;
    }


    /**
     * 分页查询运输车辆列表
     *
     * <p>查询逻辑：</p>
     * <ol>
     *   <li>分页查询运输车辆表；</li>
     *   <li>根据运输车辆ID批量查询对应普通车辆信息；</li>
     *   <li>合并数据形成响应对象。</li>
     * </ol>
     *
     * @param req 查询请求参数
     * @return 分页结果（合并普通车辆信息）
     */
    @Override
    public BasePage<TransportVehicleRes> listTransportVehicles(TransportVehicleListReq req) {
        // 启动分页，仅拦截本线程内的下一条 SQL 查询
        Page<TransportVehicleEntity> page = PageHelper.startPage(req.getPageNo(), req.getPageSize());

        QueryTransportVehicleBo queryTransportVehicleBo = new QueryTransportVehicleBo();
        BeanUtils.copyProperties(req, queryTransportVehicleBo);

        List<TransportVehicleEntity> transportVehicleEntityList = transportVehicleService.selectTransportVehicleList(queryTransportVehicleBo);

        // 收集所有运输车辆ID，用于批量查询普通车辆
        List<Long> transportIds = transportVehicleEntityList.stream().map(TransportVehicleEntity::getId).toList();

        QueryCommonVehicleBo queryCommonVehicleBo = new QueryCommonVehicleBo();
        // 设置普通车辆查询条件：关联ID列表
        queryCommonVehicleBo.setAssIds(transportIds);

        List<CommonVehicleEntity> commonVehicleEntityList = commonVehicleService.selectCommonVehicleList(queryCommonVehicleBo);
        commonVehicleEntityList = commonVehicleEntityList.stream()
                .filter(commonVehicleEntity -> commonVehicleEntity.getVehicleType().equals(VehicleTypeEnum.TRANSPORT.name())).toList();
        // 按 associationId 将普通车辆分组，方便后续匹配
        Map<Long, List<CommonVehicleEntity>> commonAssGroup = commonVehicleEntityList.stream().collect(Collectors.groupingBy(CommonVehicleEntity::getAssociationId));

        List<TransportVehicleRes> list = transportVehicleEntityList.stream().map(transportVehicleEntity -> {
            TransportVehicleRes transportVehicleRes = new TransportVehicleRes();
            BeanUtils.copyProperties(transportVehicleEntity, transportVehicleRes);
            CommonVehicleEntity commonVehicleEntity = commonAssGroup.get(transportVehicleEntity.getId()).get(0);

            if (commonVehicleEntity != null) {
                // 合并普通车辆信息字段到响应对象
                BeanUtils.copyProperties(commonVehicleEntity, transportVehicleRes);
            }
            return transportVehicleRes;
        }).toList();
        // 封装分页结果并返回
        return BasePage.generateResult(page.getPages(), page.getTotal(), list);
    }
}